事务控制的3种方式
编程式事务
:直接在代码里手动开启事务,手动提交,手动回滚
。优点就是可以灵活控制,缺点就是太麻烦了,太多重复的代码了
。声明式事务
:就是使用Spring Aop配置事务
,这种方式简化了编码。需要注意的是切入点表达式一定要写正确。注解事务
:直接在Service层的方法上面加上@Transactional注解
,最简单方便的方式。
伪代码
排序往后的方法报错,导致排序前的方法不回滚
,如下:updataFlag
方法出错,analyseRedBall
和 analyseBlueBall
方法不会回滚
public void statistics() { |
为什么不会滚呢
Spring默认情况
下是捕获到方法的RuntimeException
异常,也就是说只要属于RuntimeException
异常或及其子类
都能回滚。不属于运行时异常时,事务不回滚的。
解决方案
声明式事务
确保切入点表达式
书写正确,如在配置里面添加rollback-for
<tx:method name="update*" propagation="REQUIRED" rollback-for="java.lang.Exception"/> |
注解事务
使用位置
类上
:该类的所有public 方法
将都具有务属性方法上
:只能应用到 public 方法上,这是由Spring AOP的本质决定的,如果在protected、private
或者默认可见性的方法上
使用 @Transactional 注解,将被忽略,也不会抛出任何异常。接口、接口方法上
:接口实现类或接口实现方法可继承事务属性,Spring 建议不要在接口或者接口方法上使用该注解,因为这只有在使用基于接口的代理时它才会生效
基本用法
将Spring默认的RuntimeException
异常修改为Exception
异常,可以保证任何异常都可以回滚。
或指定多个异常
如上述实例修改为
|
异常抛出
在catch语句中抛出异常
,以便让Aop捕获异常执行回滚事务
,如下伪代码
|
手动事务
配合事务注解@Transactional
,手动处理事务回滚
设置回滚代码
在catch语句中设置回滚代码
来实现回滚,此方法在抛出异常后也能return 返回值,适合需要拿到返回值的场景
|
设置回滚点
// 方法返回的是object类型,o 为回滚点变量名 |
存储引擎
到此之前,代码无误,那为什么 Spring 或 SpringBoot 的事务回滚还是没有任何效果呢?
数据库肯定是
MySQL
,那表的存储引擎,也要支持事务安全才行
,最重要,也是最多人忽视的地方;InnoDB 和 BDB 提供事务安全表,其他存储引擎都是非事务安全表
注:
Oracleb不存在存储引擎的概念
,数据处理大致可以分成两大类:联机事务处理OLTP
(on-line transaction processing)、联机分析处理OLAP
(On-Line Analytical Processing)。
- OLTP是
传统的关系型数据库
的主要应用,主要是基本的、日常的事务处理,例如银行交易。强调数据库内存效率,强调内存各种指标的命令率,强调绑定变量,强调并发操作
- OLAP是
数据仓库系统
的主要应用,支持复杂的分析操作,侧重决策支持,并且提供直观易懂的查询结果。强调数据分析,强调SQL执行市场,强调磁盘I/O,强调分区等
总结
@Transactional和@Transactional(rollbackFor = Exception.class)的区别
@Transactional
只能回滚RuntimeException
和RuntimeException的子类
抛出的异常,不能回滚Exception异常- 如果需要支持回滚
Exception异常
请用@Transactional(rollbackFor = Exception.class)
增删改
建议使用@Transactional(rollbackFor = Exception.class)
@Transactional(rollbackFor = Exception.class)的失效场景
- 不是
public修饰
try...catch...
捕获了异常(没在catch里面手动抛出异常
)- 没有加
@Service
(没被 Spring 管理
)